package cn.mju.tankfighterbackend.service.game

import cn.mju.tankfighterbackend.dao.GameRepository
import cn.mju.tankfighterbackend.entity.game.Game
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

@Service
class GameService @Autowired constructor(
   private val gameRepository: GameRepository,
   private val gameServer: GameServer
){

    //Int->4位房间号 Long-> gameId
    private final val houseCodeCache:Cache<Int,Long> = Caffeine.newBuilder().expireAfterWrite(5,TimeUnit.MINUTES).build()

    private val houseCodeGenerator = AtomicInteger(1000)

    /**
     * 获取下一个房间号 并且创建与游戏的关联
     * @return 绑定的房间号 -1表示绑定失败 所有可用房间号被占满
     */
    @Synchronized
    private fun bindToNextHouseCode(gameId: Long):Int{
        var next = houseCodeGenerator.incrementAndGet()
        for (i in 0..10000){
            if(next>9999){
                houseCodeGenerator.set(1000)
            }
            if(houseCodeCache.getIfPresent(next)==null){
                houseCodeCache.put(next,gameId)
                return next
            }
            next = houseCodeGenerator.incrementAndGet()
        }
        return -1
    }
    /**
     * 创建一个新的游戏
     * @return <gameId,houseCode>
     */
    @Transactional
    fun createNewGame(playerCount:Int):Result<Pair<Long,Int>>{
        val game = Game()
        game.maxPlayerCount = playerCount
        gameRepository.save(game)
        val gameExecutor = GameExecutor(game)
        gameServer.registerGame(gameExecutor)
        val houseCode = bindToNextHouseCode(game.id!!)
        if(houseCode==-1){
            gameRepository.delete(game)
            return Result.failure(Exception("获取房间号失败!,请稍后重试"))
        }

        return Result.success( Pair(game.id!!,houseCode))
    }


    /**
     * 根据房间号获取gameId
     * @return gameId
     */
    fun getGameIdByHouseCode(houseCode:Int):Long?{
      return houseCodeCache.getIfPresent(houseCode)
    }

    /**
     * 根据用户名获取gameId
     * @return gameId
     */
    fun getGameIdByPlayer(userName:String):Long?{
        return gameServer.playerInGame[userName];
    }



    /**
     * 加入一个游戏房间
     * @return gameId
     */
    fun getPlayerNamesInGame(gameId:Long):List<String>?{

        gameServer.games[gameId]?.let { gameExecutor ->
         return@getPlayerNamesInGame  gameExecutor.getPlayerNamesList()
        }
        return null
    }

    /**
     * 加入一个游戏房间
     * @return gameId
     */
    fun joinGame(houseCode: Int,userName:String):Result<Long>{
        houseCodeCache.getIfPresent(houseCode)?.let { gameId->
            gameServer.games[gameId]?.let { gameExecutor ->
                val playerId = gameExecutor.tryJoinGame(userName)
                if(playerId!=-1){
                    gameServer.playerInGame[userName] = gameId
                    return  Result.success(gameId)
                }
                return Result.failure(Exception("房间满了"))
            }
        }

        return Result.failure(Exception("房间号不存在"))
    }
    /**
     * 退出一个游戏房间
     *
     */
    fun exitGame(userName:String):Boolean{
        gameServer.playerInGame[userName]?.let {gameId->
            gameServer.games[gameId]?.let { gameExecutor ->
                if (gameExecutor.exitGame(userName)) {
                    return true
                }
            }
        }
        return false
    }
}